// PART OF THE MACHINE SIMULATION. DO NOT CHANGE.
package mysgoog.brown;

import java.io.*;
import java.lang.reflect.*;
import java.util.*;

/**
 * Thrown when an assertion fails.
 */
@SuppressWarnings("serial")
class AssertionFailureError extends Error
{
    AssertionFailureError()
    {
        super();
    }
    AssertionFailureError(String message)
    {
        super(message);
    }
}

/**
 * Provides miscellaneous library routines.
 */
@SuppressWarnings("unchecked")
public final class Lib
{
    /**
     * Prevent instantiation.
     */
    private Lib()
    {
    }

    private static boolean run = true;

    public static void log(String txt)
    {
        if (run)
            return;
        try
        {
            FileOutputStream fos = new FileOutputStream("BrownLog.txt", true);
            PrintStream ps = new PrintStream(fos);
            ps.println(txt);
            ps.flush();
            ps.close();
        }
        catch (FileNotFoundException e)
        {
            e.printStackTrace();
        }
    }

    private static Random random = new Random(0);

    /**
     * Seed the random number generater. May only be called once.
     * 
     * @param randomSeed
     *            the seed for the random number generator.
     */
    public static void seedRandom(long randomSeed)
    {
        assertTrue(random == null);
        random = new Random(randomSeed);
    }
    /**
     * Return a random integer between 0 and <i>range - 1</i>. Must not be
     * called before <tt>seedRandom()</tt> seeds the random number generator.
     * 
     * @param range
     *            a positive value specifying the number of possible return
     *            values.
     * @return a random integer in the specified range.
     */
    public static int random(int range)
    {
        assertTrue(range > 0);
        return random.nextInt(range);
    }
    /**
     * Return a random double between 0.0 (inclusive) and 1.0 (exclusive).
     * 
     * @return a random double between 0.0 and 1.0.
     */
    public static double random()
    {
        return random.nextDouble();
    }
    /**
     * Asserts that <i>expression</i> is <tt>true</tt>. If not, then Nachos
     * exits with an error message.
     * 
     * @param expression
     *            the expression to assert.
     */
    public static void assertTrue(boolean expression)
    {
        if (!expression)
        {
            Lib.log("Lib error!");
            throw new AssertionFailureError();
        }
    }
    /**
     * Asserts that <i>expression</i> is <tt>true</tt>. If not, then Nachos
     * exits with the specified error message.
     * 
     * @param expression
     *            the expression to assert.
     * @param message
     *            the error message.
     */
    public static void assertTrue(boolean expression, String message)
    {
        if (!expression)
            throw new AssertionFailureError(message);
    }
    /**
     * Asserts that this call is never made. Same as <tt>assertTrue(false)</tt>.
     */
    public static void assertNotReached()
    {
        assertTrue(false);
    }
    /**
     * Asserts that this call is never made, with the specified error messsage.
     * Same as <tt>assertTrue(false, message)</tt>.
     * 
     * @param message
     *            the error message.
     */
    public static void assertNotReached(String message)
    {
        assertTrue(false, message);
    }
    /**
     * Print <i>message</i> if <i>flag</i> was enabled on the command line. To
     * specify which flags to enable, use the -d command line option. For
     * example, to enable flags a, c, and e, do the following:
     * 
     * <p>
     * 
     * <pre>
     * nachos -d ace
     * </pre>
     * 
     * <p>
     * Nachos uses several debugging flags already, but you are encouraged to
     * add your own.
     * 
     * @param flag
     *            the debug flag that must be set to print this message.
     * @param message
     *            the debug message.
     */
    public static void debug(char flag, String message)
    {
        if (test(flag))
            System.out.println(message);
    }
    /**
     * Tests if <i>flag</i> was enabled on the command line.
     * 
     * @param flag
     *            the debug flag to test.
     * 
     * @return <tt>true</tt> if this flag was enabled on the command line.
     */
    public static boolean test(char flag)
    {
        if (debugFlags == null)
            return false;
        else if (debugFlags[(int) '+'])
            return true;
        else if (flag >= 0 && flag < 0x80 && debugFlags[(int) flag])
            return true;
        else
            return false;
    }
    /**
     * Enable all the debug flags in <i>flagsString</i>.
     * 
     * @param flagsString
     *            the flags to enable.
     */
    public static void enableDebugFlags(String flagsString)
    {
        if (debugFlags == null)
            debugFlags = new boolean[0x80];
        char[] newFlags = flagsString.toCharArray();
        for (int i = 0; i < newFlags.length; i++)
        {
            char c = newFlags[i];
            if (c >= 0 && c < 0x80)
                debugFlags[(int) c] = true;
        }
    }

    /** Debug flags specified on the command line. */
    private static boolean debugFlags[];

    /**
     * Convert a short into its little-endian byte string representation.
     * 
     * @param array
     *            the array in which to store the byte string.
     * @param offset
     *            the offset in the array where the string will start.
     * @param value
     *            the value to convert.
     */
    public static void bytesFromShort(byte[] array, int offset, short value)
    {
        array[offset + 0] = (byte) ((value >> 0) & 0xFF);
        array[offset + 1] = (byte) ((value >> 8) & 0xFF);
    }
    /**
     * Convert an int into its little-endian byte string representation.
     * 
     * @param array
     *            the array in which to store the byte string.
     * @param offset
     *            the offset in the array where the string will start.
     * @param value
     *            the value to convert.
     */
    public static void bytesFromInt(byte[] array, int offset, int value)
    {
        array[offset + 0] = (byte) ((value >> 0) & 0xFF);
        array[offset + 1] = (byte) ((value >> 8) & 0xFF);
        array[offset + 2] = (byte) ((value >> 16) & 0xFF);
        array[offset + 3] = (byte) ((value >> 24) & 0xFF);
    }
    /**
     * Convert an int into its little-endian byte string representation, and
     * return an array containing it.
     * 
     * @param value
     *            the value to convert.
     * @return an array containing the byte string.
     */
    public static byte[] bytesFromInt(int value)
    {
        byte[] array = new byte[4];
        bytesFromInt(array, 0, value);
        return array;
    }
    /**
     * Convert an int into a little-endian byte string representation of the
     * specified length.
     * 
     * @param array
     *            the array in which to store the byte string.
     * @param offset
     *            the offset in the array where the string will start.
     * @param length
     *            the number of bytes to store (must be 1, 2, or 4).
     * @param value
     *            the value to convert.
     */
    public static void bytesFromInt(byte[] array, int offset, int length, int value)
    {
        assertTrue(length == 1 || length == 2 || length == 4);
        switch (length)
        {
            case 1 :
                array[offset] = (byte) value;
                break;
            case 2 :
                bytesFromShort(array, offset, (short) value);
                break;
            case 4 :
                bytesFromInt(array, offset, value);
                break;
        }
    }
    /**
     * Convert to a short from its little-endian byte string representation.
     * 
     * @param array
     *            the array containing the byte string.
     * @param offset
     *            the offset of the byte string in the array.
     * @return the corresponding short value.
     */
    public static short bytesToShort(byte[] array, int offset)
    {
        return (short) ((((short) array[offset + 0] & 0xFF) << 0) | (((short) array[offset + 1] & 0xFF) << 8));
    }
    /**
     * Convert to an unsigned short from its little-endian byte string
     * representation.
     * 
     * @param array
     *            the array containing the byte string.
     * @param offset
     *            the offset of the byte string in the array.
     * @return the corresponding short value.
     */
    public static int bytesToUnsignedShort(byte[] array, int offset)
    {
        return (((int) bytesToShort(array, offset)) & 0xFFFF);
    }
    /**
     * Convert to an int from its little-endian byte string representation.
     * 
     * @param array
     *            the array containing the byte string.
     * @param offset
     *            the offset of the byte string in the array.
     * @return the corresponding int value.
     */
    public static int bytesToInt(byte[] array, int offset)
    {
        return (int) ((((int) array[offset + 0] & 0xFF) << 0)
                | (((int) array[offset + 1] & 0xFF) << 8)
                | (((int) array[offset + 2] & 0xFF) << 16) | (((int) array[offset + 3] & 0xFF) << 24));
    }
    /**
     * Convert to an int from a little-endian byte string representation of the
     * specified length.
     * 
     * @param array
     *            the array containing the byte string.
     * @param offset
     *            the offset of the byte string in the array.
     * @param length
     *            the length of the byte string.
     * @return the corresponding value.
     */
    public static int bytesToInt(byte[] array, int offset, int length)
    {
        assertTrue(length == 1 || length == 2 || length == 4);
        switch (length)
        {
            case 1 :
                return array[offset];
            case 2 :
                return bytesToShort(array, offset);
            case 4 :
                return bytesToInt(array, offset);
            default :
                return -1;
        }
    }
    /**
     * Convert to a string from a possibly null-terminated array of bytes.
     * 
     * @param array
     *            the array containing the byte string.
     * @param offset
     *            the offset of the byte string in the array.
     * @param length
     *            the maximum length of the byte string.
     * @return a string containing the specified bytes, up to and not including
     *         the null-terminator (if present).
     */
    public static String bytesToString(byte[] array, int offset, int length)
    {
        int i;
        for (i = 0; i < length; i++)
        {
            if (array[offset + i] == 0)
                break;
        }
        return new String(array, offset, i);
    }
    /**
     * Mask out and shift a bit substring.
     * 
     * @param bits
     *            the bit string.
     * @param lowest
     *            the first bit of the substring within the string.
     * @param size
     *            the number of bits in the substring.
     * @return the substring.
     */
    public static int extract(int bits, int lowest, int size)
    {
        if (size == 32)
            return (bits >> lowest);
        else
            return ((bits >> lowest) & ((1 << size) - 1));
    }
    /**
     * Mask out and shift a bit substring.
     * 
     * @param bits
     *            the bit string.
     * @param lowest
     *            the first bit of the substring within the string.
     * @param size
     *            the number of bits in the substring.
     * @return the substring.
     */
    public static long extract(long bits, int lowest, int size)
    {
        if (size == 64)
            return (bits >> lowest);
        else
            return ((bits >> lowest) & ((1L << size) - 1));
    }
    /**
     * Mask out and shift a bit substring; then sign extend the substring.
     * 
     * @param bits
     *            the bit string.
     * @param lowest
     *            the first bit of the substring within the string.
     * @param size
     *            the number of bits in the substring.
     * @return the substring, sign-extended.
     */
    public static int extend(int bits, int lowest, int size)
    {
        int extra = 32 - (lowest + size);
        return ((extract(bits, lowest, size) << extra) >> extra);
    }
    /**
     * Test if a bit is set in a bit string.
     * 
     * @param flag
     *            the flag to test.
     * @param bits
     *            the bit string.
     * @return <tt>true</tt> if <tt>(bits & flag)</tt> is non-zero.
     */
    public static boolean test(long flag, long bits)
    {
        return ((bits & flag) != 0);
    }
    /**
     * Creates a padded upper-case string representation of the integer argument
     * in base 16.
     * 
     * @param i
     *            an integer.
     * @return a padded upper-case string representation in base 16.
     */
    public static String toHexString(int i)
    {
        return toHexString(i, 8);
    }
    /**
     * Creates a padded upper-case string representation of the integer argument
     * in base 16, padding to at most the specified number of digits.
     * 
     * @param i
     *            an integer.
     * @param pad
     *            the minimum number of hex digits to pad to.
     * @return a padded upper-case string representation in base 16.
     */
    public static String toHexString(int i, int pad)
    {
        String result = Integer.toHexString(i).toUpperCase();
        while (result.length() < pad)
            result = "0" + result;
        return result;
    }
    /**
     * Divide two non-negative integers, round the quotient up to the nearest
     * integer, and return it.
     * 
     * @param a
     *            the numerator.
     * @param b
     *            the denominator.
     * @return <tt>ceiling(a / b)</tt>.
     */
    public static int divRoundUp(int a, int b)
    {
        assertTrue(a >= 0 && b > 0);
        return ((a + (b - 1)) / b);
    }
    /**
     * Load and return the named class, or return <tt>null</tt> if the class
     * could not be loaded.
     * 
     * @param className
     *            the name of the class to load.
     * @return the loaded class, or <tt>null</tt> if an error occurred.
     */
    public static Class tryLoadClass(String className)
    {
        try
        {
            return ClassLoader.getSystemClassLoader().loadClass(className);
        }
        catch (Throwable e)
        {
            return null;
        }
    }
    /**
     * Verify that the specified class extends or implements the specified
     * superclass.
     * 
     * @param cls
     *            the descendant class.
     * @param superCls
     *            the ancestor class.
     */
    public static void checkDerivation(Class<?> cls, Class<?> superCls)
    {
        Lib.assertTrue(superCls.isAssignableFrom(cls));
    }
    /**
     * Verifies that the specified class is public and not abstract, and that a
     * constructor with the specified signature exists and is public.
     * 
     * @param cls
     *            the class containing the constructor.
     * @param parameterTypes
     *            the list of parameters.
     */
    public static void checkConstructor(Class cls, Class[] parameterTypes)
    {
        try
        {
            Lib.assertTrue(Modifier.isPublic(cls.getModifiers())
                    && !Modifier.isAbstract(cls.getModifiers()));
            Constructor constructor = cls.getConstructor(parameterTypes);
            Lib.assertTrue(Modifier.isPublic(constructor.getModifiers()));
        }
        catch (Exception e)
        {
            Lib.assertNotReached();
        }
    }
    /**
     * Verifies that the specified class is public, and that a non-static method
     * with the specified name and signature exists, is public, and returns the
     * specified type.
     * 
     * @param cls
     *            the class containing the non-static method.
     * @param methodName
     *            the name of the non-static method.
     * @param parameterTypes
     *            the list of parameters.
     * @param returnType
     *            the required return type.
     */
    public static void checkMethod(Class cls, String methodName, Class[] parameterTypes,
            Class returnType)
    {
        try
        {
            Lib.assertTrue(Modifier.isPublic(cls.getModifiers()));
            Method method = cls.getMethod(methodName, parameterTypes);
            Lib.assertTrue(Modifier.isPublic(method.getModifiers())
                    && !Modifier.isStatic(method.getModifiers()));
            Lib.assertTrue(method.getReturnType() == returnType);
        }
        catch (Exception e)
        {
            Lib.assertNotReached();
        }
    }
    /**
     * Verifies that the specified class is public, and that a static method
     * with the specified name and signature exists, is public, and returns the
     * specified type.
     * 
     * @param cls
     *            the class containing the static method.
     * @param methodName
     *            the name of the static method.
     * @param parameterTypes
     *            the list of parameters.
     * @param returnType
     *            the required return type.
     */
    public static void checkStaticMethod(Class cls, String methodName, Class[] parameterTypes,
            Class returnType)
    {
        try
        {
            Lib.assertTrue(Modifier.isPublic(cls.getModifiers()));
            Method method = cls.getMethod(methodName, parameterTypes);
            Lib.assertTrue(Modifier.isPublic(method.getModifiers())
                    && Modifier.isStatic(method.getModifiers()));
            Lib.assertTrue(method.getReturnType() == returnType);
        }
        catch (Exception e)
        {
            Lib.assertNotReached();
        }
    }
    /**
     * Verifies that the specified class is public, and that a non-static field
     * with the specified name and type exists, is public, and is not final.
     * 
     * @param cls
     *            the class containing the field.
     * @param fieldName
     *            the name of the field.
     * @param fieldType
     *            the required type.
     */
    public static void checkField(Class cls, String fieldName, Class fieldType)
    {
        try
        {
            Lib.assertTrue(Modifier.isPublic(cls.getModifiers()));
            Field field = cls.getField(fieldName);
            Lib.assertTrue(field.getType() == fieldType);
            Lib.assertTrue(Modifier.isPublic(field.getModifiers())
                    && !Modifier.isStatic(field.getModifiers())
                    && !Modifier.isFinal(field.getModifiers()));
        }
        catch (Exception e)
        {
            Lib.assertNotReached();
        }
    }
    /**
     * Verifies that the specified class is public, and that a static field with
     * the specified name and type exists and is public.
     * 
     * @param cls
     *            the class containing the static field.
     * @param fieldName
     *            the name of the static field.
     * @param fieldType
     *            the required type.
     */
    public static void checkStaticField(Class cls, String fieldName, Class fieldType)
    {
        try
        {
            Lib.assertTrue(Modifier.isPublic(cls.getModifiers()));
            Field field = cls.getField(fieldName);
            Lib.assertTrue(field.getType() == fieldType);
            Lib.assertTrue(Modifier.isPublic(field.getModifiers())
                    && Modifier.isStatic(field.getModifiers()));
        }
        catch (Exception e)
        {
            Lib.assertNotReached();
        }
    }
}
